# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'qtMainWindows.ui'
#
# Created: Thu Jul 18 18:17:23 2013
#      by: pyside-uic 0.2.14 running on PySide 1.2.0
#
# WARNING! All changes made in this file will be lost!

import sys
import math
import re
import dockwidgets_rc
import functools
import inspect
import logging

from libatomism import *

from PySide import QtCore, QtGui, QtWebKit
from Widgets import *
from ScriptWidget import *
from PopUpBox import *

from TreeMapperModel import *
from AttributsEditor import *
from Misc import *

from msXmlLoader import *
from msXmlWritter import *

from WidgetsContainer import *
         
class MainWindow(QtGui.QMainWindow):
    
    rootObject = msTreeMapper.New()
    """ This class defines the main windows
    """
    def __init__(self):
        super(MainWindow, self).__init__()
        
        self.setWindowTitle("atomism development interface")
        self.setUnifiedTitleAndToolBarOnMac(True)        
        
        self.initUI()
        
        # python logger
        dialogHandler = QtStreamHandler(self.outStream,  self)
        logging.basicConfig(level=logging.DEBUG)
        logging.getLogger().addHandler(dialogHandler)
        
        # atomism logger
        msLogger.setPriorityMin(Priority.DEBUG)
        
        # new object root
        self.rootObject.setId("workspace")
        self.setRootObject()
        
    @staticmethod
    def getObject():
        return MainWindow.rootObject
        
    def initUI(self):
        """ initialize the graphical interface elements: 
        the script widget (central element), the toolbars and the dock's parts
        """
        # script widget
        self.outStream = ""
        self.scriptWidget = uiScriptWidget(self)  
        self.scriptWidget.setStdOut(self.outStream)
        self.setCentralWidget(self.scriptWidget)
                
        # toolobars
        self.createMenusAndAction()
        self.createToolBars()
        
        # dock's elements        
        self.createDockElements()
        
        self.isInit = 1
        self.statusBar().showMessage("Ready")
                 
    def setRootObject( self ):
        """ load self.rootObject as root in the graphical interface
        """
        self.mainTreeModelObject = TreeMapperModel(self.rootObject,"msTreeMapper")
        self.mainTreeWidget.setModel(self.mainTreeModelObject)        


    def createDockElements(self):
        """ Create the dock's elements, initial arrangment:
        - in the left   : the tree tab (data,files,debug) and the attribut dock
        - in the bottom : Exception printer, output, and doc
        - in the right  : the graphical widgets of the selected object
        """
        
        # left dock
        mainTreeDock = QtGui.QDockWidget("", self)
        tab = QtGui.QTabWidget(mainTreeDock)
        self.mainTreeWidget = QtGui.QTreeView()
        self.mainTreeWidget.clicked.connect(self.clickTreeView)
        tab.addTab( self.mainTreeWidget, "data structure")
        
        self.browserTreeWidget = QtGui.QTreeView()
        self.browserTreeWidget.clicked.connect(self.clickFileTreeView)
        self.browserModel = QtGui.QFileSystemModel()
        self.browserModel.setRootPath(QtCore.QDir.currentPath())
        self.browserTreeWidget.setModel(self.browserModel)
        tab.addTab(self.browserTreeWidget,"browser")
        
        self.debugTreeWidget = QtGui.QTreeView()
        tab.addTab(self.debugTreeWidget, "debug")
        mainTreeDock.setWidget(tab)
        self.viewMenu.addAction(mainTreeDock.toggleViewAction())
        
        attributDock = QtGui.QDockWidget("Attributes", self)
        self.attributsList = QtGui.QTreeView(attributDock)
        attributDock.setWidget(self.attributsList)
        self.viewMenu.addAction(attributDock.toggleViewAction())
        
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, mainTreeDock)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, attributDock)
  
        # bottom dock        
        outDock   = QtGui.QDockWidget("Out", self)
        self.outStream = QtGui.QTextEdit()
        self.scriptWidget.setStdOut(self.outStream) 
        outDock.setWidget(self.outStream) 
        self.viewMenu.addAction(outDock.toggleViewAction())
        
        docDock = QtGui.QDockWidget("Documentation", self)
        docTab  = QtGui.QTabWidget()
        self.webView=QtWebKit.QWebView()
        self.webView.load("http://atomism.googlecode.com/svn/trunk/doc/html/index.html#overview")
        docTab.addTab(self.webView,"contextual")
        docDock.setWidget(docTab)
        self.viewMenu.addAction(docDock.toggleViewAction())
        
        self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, outDock)        
        self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, docDock)
        
        # right doc        
        dockGUIobjects = QtGui.QDockWidget("Graphical interface", self)
        self.msWidgetsContainer = WidgetsContainer(self)
        dockGUIobjects.setWidget(self.msWidgetsContainer)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dockGUIobjects)
        self.viewMenu.addAction(dockGUIobjects.toggleViewAction())
        
 
    def clickTreeView(self):
        """ action executed when the main tree view is clicked (i.e. an object 
        selected). Tree actions:
        update the object's methods available
        update the attributs of the object        
        update the widgets container
        update the contextual documentation
        """
        # update the methods available
        myobject = self.mainTreeWidget.currentIndex().internalPointer().getRawdata()
        self.methodsMenu.clear()
        
        for method in inspect.getmembers(myobject):
            
            helpstr=inspect.getdoc(method[1])
        
            if(not method[0][:1]=="_"):
                try:
                    if(len(helpstr.split(':'))>1):
                        helpstr=helpstr.split(':')[1].split('.')[0]
                except:
                    pass
                action = QtGui.QAction(method[0], self,
                   statusTip= helpstr,
                   triggered=functools.partial(self.execMethod, method))
           
                self.methodsMenu.addAction(action)
        
        # Update the Attributes panel
        model = AttributTreeModel(myobject)
        self.attributsList.setModel(model)   
        # update the widgets container
        self.msWidgetsContainer.update(myobject)
        
        # Update the documentation
        last = self.getDoxygenName(myobject.getType()).split(':')
        self.webView.load("http://atomism.googlecode.com/svn/trunk/doc/html/classatomism_1_1"+last[-2]+".html#details")
       
    def clickFileTreeView(self):
        """ action executed when the file tree view is clicked (i.e. an object 
        selected). If text file is selected, it is open in the editor
        """
        filename = self.browserModel.fileInfo(self.browserTreeWidget.currentIndex()).absoluteFilePath()
        file = open( filename, "r" )
        
        self.scriptWidget.addTab(filename.split('/')[-1])
        text = self.scriptWidget.currentScript()
        i=0
        for line in file:
            text.insertPlainText( line )
            i = i + 1
        
        file.close()
        text.filename = filename

    def getDoxygenName(self,name):
        s1 = re.sub('(.)([A-Z][a-z]+)',r'\1_\2',name)
        return re.sub('([a-z0-9])([A-Z])',r'\1_\2',s1).lower()
              
    def saveTree(self):
        """ Save the tree object
        """
        """ Save the current script in the associated file
        """
        print "save"
        filename, filtr = QtGui.QFileDialog.getSaveFileName(self,
                "Choose a file name", '.', "xml (*.xml)")
        if not filename:
            return
            
        writter = msXmlWritter.New()
        writter.save(MainWindow.getObject(),filename)
    
    def openTree(self):
        """ Save the tree object
        """
        filename, filtr = QtGui.QFileDialog.getOpenFileName(self,
                "Choose a file name", '.', "xml (*.xml)")
        if not filename:
            return
            
        loader = msXmlLoader.New()
        a = msTreeMapper.New()
        try:
            loader.open(a,filename)
        except:
            self.reportException("can not load the xml file")
            
        MainWindow.rootObject = a
        model = TreeModel( a ,"msTreeMapper")
        self.mainTreeWidget.setModel(model)
        
    """ 'script' menu actions
    """
    def saveScript(self):
        """ Save the current script in the associated file
        """
        text = self.scriptWidget.currentScript() 
        filename = text.filename
        if(filename==""):
            self.saveScriptAs()
            return
            
        file = QtCore.QFile(filename)
        if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(self, "Dock Widgets",
                    "Cannot write file %s:\n%s." % (filename, file.errorString()))
            return

        out = QtCore.QTextStream(file)
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        out << self.scriptWidget.tabWidget.currentWidget().toPlainText()
        QtGui.QApplication.restoreOverrideCursor()
        
        file.close()

    def saveScriptAs(self):
        """ Save the current script in a new file
        """
        filename, filtr = QtGui.QFileDialog.getSaveFileName(self,
                "Choose a file name", '.', "py (*.py)")
        if not filename:
            return

        file = QtCore.QFile(filename)
        if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(self, "Dock Widgets",
                    "Cannot write file %s:\n%s." % (filename, file.errorString()))
            return

        out = QtCore.QTextStream(file)
        QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        out << self.scriptWidget.tabWidget.currentWidget().toPlainText()
        QtGui.QApplication.restoreOverrideCursor()
        file.write(str(out))
        file.close()
        i = self.scriptWidget.tabWidget.currentIndex()
        self.scriptWidget.tabWidget.setTabText(i,filename.split('/')[-1])
        text = self.scriptWidget.currentScript() 
        text.filename = filename
        self.statusBar().showMessage("Saved '%s'" % filename, 2000)
        
    def openScript(self):
        """ Open a script from a new file
        """
        filename, filtr = QtGui.QFileDialog.getOpenFileName(self,
                "Choose a file name", '.', "py (*.py)")
        if not filename:
            return

        file = open( filename, "r" )
        
        self.scriptWidget.addTab(filename.split('/')[-1])   
        #text = QtGui.QTextEdit()
        text = self.scriptWidget.currentScript() 
        i=0
        for line in file:
            text.insertPlainText( line )
            i = i + 1
            
        file.close()
        text.filename = filename
        self.statusBar().showMessage("Open '%s'" % filename, 2000)
        
    def newScript(self):
        """ New script empty
        """
        self.scriptWidget.addTab(datetime.datetime.now().strftime("%H:%M")+"*")
        text = self.scriptWidget.currentScript() 
        text.filename = ""

    def newScriptFromTemplate(self):
        """ New script from a template
        """        
        widgetNew=uiNewScriptTemplatePopUp( self.scriptWidget )
        widgetNew.show()
        widgetNew.resize(100,400,400,400)
        
    def runScript(self,mycode):
        """ New script from a template
        """          
        exec(mycode,globals(),globals())
        self.createMenusAndAction()
 
    def insertVarInScript(self):
        """ insert the selected object in the main tree in the script at the
        cursor position
        """
        myobject = self.mainTreeWidget.currentIndex().internalPointer().getRawdata()
        name     = myobject.getFullVariableName()
        path     = "MainWindow.getObject()"
        
        if (len(name.split('-')) >1):
            for i in name.split('-')[1:]:
                path = path  + ".getChild(\""+i+"\")"
                
        self.scriptWidget.currentScript().insertPlainText(path)
        

    def newObject( self , object_cls ):
        """ Menu New-\object_cls
        
        object_cls : pointer to the class of the object 
        """
        widgetNew=uiMethodWidget(object_cls.New,self.rootObject,self)
        widgetNew.show()
        widget.resize(100,400,400,400)
        
    def execMethod( self , method ):
        """ Execute a method of the object selected in the tree
        
        method : pointer to the method to execute
        """
        widget=uiMethodWidget(method[1],self.rootObject,self)
        widget.show()
        widget.resize(100,400,400,400)

    def about(self):
        QtGui.QMessageBox.about(self, "About atomism development interface",
                "The interface is designed to facilitate the use and "
                "development of code based on the library atomism.")
                
    def runscript(self):
        self.scriptWidget.runBtn()
        
    def runscriptLine(self):
        self.scriptWidget.runLine()
        
    def runscriptSelected(self):
        self.scriptWidget.runSelected()
        self.createMenusAndAction()
        
        
    def createToolBars(self):
        self.fileToolBar = self.addToolBar("File")
        self.fileToolBar.addAction(self.saveAct)
        #self.fileToolBar.addAction(self.printAct)

        self.editToolBar = self.addToolBar("Edit")
        #self.editToolBar.addAction(self.undoAct)

    def reportException(self,error):
        logging.exception("an exception occured")
            
        
    def createActions(self):
     
        """ Create actions to link with the menu items that are not context
        dependant. Action and menu that are context dependant are created 
        in the function createActionMenuContextual
        """
                
        self.saveAct = QtGui.QAction(QtGui.QIcon(':/images/save.png'),
                "&Save database...", self, shortcut=QtGui.QKeySequence(self.tr("Ctrl+Alt+S")),
                statusTip="Save the database",
                triggered=self.saveTree)
                
        self.openAct = QtGui.QAction(QtGui.QIcon(':/images/save.png'),
                "&Open database...", self, shortcut=QtGui.QKeySequence(self.tr("Ctrl+Alt+O")),
                statusTip="Load a database",
                triggered=self.openTree)
                
        self.newScriptAct = QtGui.QAction(QtGui.QIcon(':/images/new.png'),
                "&New...", self, shortcut=QtGui.QKeySequence.New,
                statusTip="New empty script",
                triggered=self.newScript)
  
        self.newScriptTemplateAct = QtGui.QAction(QtGui.QIcon(':/images/new.png'),
                "&New from template...", self, shortcut=QtGui.QKeySequence(self.tr("Ctrl+Shift+N")),
                statusTip="New script from template",
                triggered=self.newScriptFromTemplate)
                
        self.openScriptAct = QtGui.QAction(QtGui.QIcon(':/images/open.png'),
                "&Open...", self, shortcut=QtGui.QKeySequence.Open,
                statusTip="open a file",
                triggered=self.openScript)
                
        self.saveScriptAct = QtGui.QAction(QtGui.QIcon(':/images/save.png'),
                "&Save...", self, shortcut=QtGui.QKeySequence.Save,
                statusTip="Save the current script",
                triggered=self.saveScript)

        self.saveAsScriptAct = QtGui.QAction(QtGui.QIcon(':/images/save.png'),
                "SaveAs...", self, shortcut=QtGui.QKeySequence.SaveAs,
                statusTip="Save the current script as a new file",
                triggered=self.saveScriptAs)
       
        self.closeScriptAct = QtGui.QAction(QtGui.QIcon(':/images/close.png'),
                "&Close", self, shortcut=QtGui.QKeySequence.Close,
                statusTip="Close the current script", triggered=self.scriptWidget.closeCurrent)
        
        self.quitAct = QtGui.QAction("&Quit", self, shortcut="Ctrl+Q",
                statusTip="Quit the application", triggered=self.close)

        self.aboutAct = QtGui.QAction("&About", self,
                statusTip="Show the application's About box",
                triggered=self.about)
        
        self.copyScriptAct = QtGui.QAction(QtGui.QIcon(':/images/copy.png'),
                "&Copy", self, shortcut=QtGui.QKeySequence.Copy,
                statusTip="Copy text selection", triggered=self.scriptWidget.copy)
        
        self.cutScriptAct = QtGui.QAction(QtGui.QIcon(':/images/cut.png'),
                "&Cut", self, shortcut=QtGui.QKeySequence.Cut,
                statusTip="Cut text selection", triggered=self.scriptWidget.cut)
                
        self.pasteScriptAct = QtGui.QAction(QtGui.QIcon(':/images/paste.png'),
                "&Paste", self, shortcut=QtGui.QKeySequence.Paste,
                statusTip="Paste text", triggered=self.scriptWidget.paste)
                
        self.undoScriptAct = QtGui.QAction(QtGui.QIcon(':/images/undo.png'),
                "&Undo", self, shortcut=QtGui.QKeySequence.Undo,
                statusTip="Undo last action", triggered=self.scriptWidget.undo)
                
        self.redoScriptAct = QtGui.QAction(QtGui.QIcon(':/images/redo.png'),
                "&Redo", self, shortcut=QtGui.QKeySequence.Redo,
                statusTip="Redo last action", triggered=self.scriptWidget.redo)
                
        self.deleteScriptAct = QtGui.QAction(QtGui.QIcon(':/images/delete.png'),
                "&Delete", self, shortcut=QtGui.QKeySequence.Delete,
                statusTip="Delete selection", triggered=self.scriptWidget.delete)
                       
        self.insertVarInScriptAct = QtGui.QAction(QtGui.QIcon(':/images/insertVarInScriptAct.png'),
                "&Get selected var", self, shortcut=QtGui.QKeySequence(self.tr("Ctrl+I")),
                statusTip="Get the variable selected in the tree list into the script", triggered=self.insertVarInScript )
        
        self.runScriptAct = QtGui.QAction(QtGui.QIcon(':/images/run.png'),
                "Run", self, shortcut=QtGui.QKeySequence(QtCore.Qt.Key_F5),
                statusTip="Run the current script", triggered=self.runscript)
 
        self.runLineScriptAct = QtGui.QAction(QtGui.QIcon(':/images/runLine.png'),
                "Run current line", self, shortcut=QtGui.QKeySequence(QtCore.Qt.Key_F3),
                statusTip="Run the current line of the script", triggered=self.runscriptLine)
 
        self.runSelectedScriptAct = QtGui.QAction(QtGui.QIcon(':/images/runSelected.png'),
                "Run the selection", self, shortcut=QtGui.QKeySequence(QtCore.Qt.Key_F4),
                statusTip="Run the current selection of the script", triggered=self.runscriptSelected)
              
    def createActionMenuContextual(self,menu,cls):
        """ Create the 'New' menu: list the class available for a new object
        (i.e. deriving from msTreeMapper). The menu's item are listed as the 
        class heritance diagramm. A recursive scheme is used.
        """
        if(len(cls.__subclasses__())==0):
            return
        name = str(cls).split('.')[1].split('\'')[0]
        
        newAction = menu.addAction(name)
        submenu = QtGui.QMenu(str(cls),self)
        
        for cls in cls.__subclasses__():
            name =  str(cls)
            if( len(name.split('\''))>1 ):
                name = name.split('\'')[1]
            if( len(name.split('.'))>1 ):
                name = name.split('.')[1]        
                
            action = QtGui.QAction(name, self,
                   statusTip="create a new object",
                   triggered=functools.partial(self.newObject, cls))
            submenu.addAction(action)
            self.createActionMenuContextual(submenu,cls)
        newAction.setMenu(submenu)
        
    def createMenusAndAction(self):
        """ this function create the menu and their associated action 
        """
        self.createActions()    
        self.menuBar().clear()
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.newScriptAct)
        self.fileMenu.addAction(self.newScriptTemplateAct)
        self.fileMenu.addAction(self.openScriptAct)
        self.fileMenu.addAction(self.saveScriptAct)
        self.fileMenu.addAction(self.saveAsScriptAct)     
        self.fileMenu.addAction(self.closeScriptAct)
        self.fileMenu.addSeparator()       
        self.fileMenu.addAction(self.quitAct)

        self.newobjMenu = self.menuBar().addMenu("&New object")
        self.createActionMenuContextual( self.newobjMenu , msTreeMapper)

        self.methodsMenu = self.menuBar().addMenu("&Methods")
        
        self.editionMenu = self.menuBar().addMenu("&Edit")
        self.editionMenu.addAction(self.undoScriptAct)
        self.editionMenu.addAction(self.redoScriptAct)
        self.editionMenu.addSeparator()
        
        self.editionMenu.addAction(self.cutScriptAct)
        self.editionMenu.addAction(self.copyScriptAct)
        self.editionMenu.addAction(self.pasteScriptAct)
        self.editionMenu.addAction(self.deleteScriptAct)    
        
        self.findMenu = self.menuBar().addMenu("&Search") 

        self.insertMenu = self.menuBar().addMenu("&Insert") 
        self.insertMenu.addAction(self.insertVarInScriptAct)
        
        self.runMenu = self.menuBar().addMenu("&Run") 
        self.runMenu.addAction(self.runScriptAct)
        self.runMenu.addAction(self.runSelectedScriptAct)
        self.runMenu.addAction(self.runLineScriptAct)
        
        self.viewMenu = self.menuBar().addMenu("&View")

        self.helpMenu = self.menuBar().addMenu("&Help")
        self.helpMenu.addAction(self.aboutAct)
